/*
 +----------------------------------------------------------------------
 + Title        : websocket
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2023-08-10
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : websocket操作工具
 +----------------------------------------------------------------------
*/

import type { Message } from "@/types/chat"
import { nextTick, ref } from "vue"
import dayjs from 'dayjs'
import { useCommonStore, useUserStore } from "@/stores"

// 指定url
// const url = ref<string>('ws://127.0.0.1:7272?uid='+ fromUid.value +'&username=杀戮天君'+ '&group=trident')

const url = ref<string>('')

// socket是否打开,用于支付宝小程序
// 由于支付宝小程序只能使用旧版本方式操作websocket
export const socketIsOpen = ref<boolean>(false)

// 定义WebSocket
export const websocket = ref()

// 定义消息列表
export const messageList = ref<Message[]>([])

// 当前重连次数
const retries = ref(0)

// 重连间隔时间（毫秒）
const reconnectInterval = ref(3000);

// 最大重连次数
const maxRetries = ref(5);

// 客户端的心跳周期应该要比服务端小一些
// 心跳间隔为30秒
const heartbeatInterval = 30 * 1000;

// 心跳超时时间为50秒
const heartbeatTimeout = 60 * 1000;

// 心跳间隔Id
const heartbeatIntervalId = ref()

// 心跳超时Id
const heartbeatTimeoutId = ref()

// 设置URL
export const setUrl = (value: string) => {
    url.value = value
}

// ------------ 初始化 websocket 开始 ------------
export const initWebSocket = () => {
    websocket.value = uni.connectSocket({
        url: url.value,
        // success: () => {
        //     console.log('连接成功');
        // },
        // fail: (err) => {
        //     console.error('连接失败', err);
        // },
        complete: ()=> {}
    })

    // 用户存储
    const userStore = useUserStore()

    // 公共存储
    const commonStore = useCommonStore()

    // 支付宝小程序只能使用websocket旧版模式
    // #ifdef MP-ALIPAY
    // 监听连接事件
    uni.onSocketOpen((data: any) => {
        console.log('-------- Listen onOpen event --------')
        console.log('open data = ', data);
        
        // 心跳检测
        startHeartbeat()
    })

    // 监听消息事件
    uni.onSocketMessage((message: any) => {
        handleMessage(message)
    })

    // 监听错误事件
    uni.onSocketError((data: any) => {
        console.log('-------- Listen onError event --------')
        console.log('close data = ', data)
    })

    // 监听关闭事件
    uni.onSocketClose((data: any) =>  {
        console.log('-------- Listen onClose event --------')
        console.log('close data = ', data)
        

        // 连接关闭时清除定时器
        clearInterval(heartbeatIntervalId.value)
        clearTimeout(heartbeatTimeoutId.value)

        // 断线重连
        reconnect(reconnectInterval.value, maxRetries.value)
    })
    // #else
    // H5、微信小程序。。。
    // 监听连接事件
    websocket.value.onOpen((data: any) => {
        console.log('-------- Listen onOpen event --------')
        console.log('open data = ', data);
        
        // 心跳检测
        startHeartbeat()
    })

    // 监听消息事件
    websocket.value.onMessage(async (message: any) => {
        console.log('------- Listen onMessage event -------')
        const response = JSON.parse(message.data)
        // console.log('response = ', response)

        // 判断消息状态
        if (response.status_code != 200) {
            uni.showToast({
                title: response.msg,
                duration: 1000,
                icon: 'none'
            })
    
            return false
        }

        // 解析数据
        const data = response.data
        
        // 处理事件
        switch (data.event_type) {
            case 'receive-private-chat': // 接收私聊消息事件
                console.log(' -------------- 接收私聊消息事件 -------------- ')
                console.log('data =', data);
                // 如果当前页面是聊天页面,则发送设置消息为已读消息
                if (commonStore.currentRouteUrl == '/pages/chat/index') {
                    console.log(' +++++++++++++ 设置消息为已读 +++++++++++++ ')
                    // 设置消息为已读
                    data.is_read = 1
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })

                    // loadingInstance.value.close()
                    messageList.value.unshift(data);
                    console.log('receive-private-chat =', data);
                }

                // 如果当前页不是聊天页面,则打开对话框、将最后一条消息修改为当前消息
                if (commonStore.currentRouteUrl != '/pages/chat/index') {
                    console.log(' +++++++++++++ 打开聊天对象 +++++++++++++ ')
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'open-chat-target',
                            uid: data.to_uid,
                            mode: 1,
                            target_info: {
                                name: data.from_user?.username,
                                target_id: data.from_user?.uid,
                                avatar_url: data.from_user?.avatar_url
                            }
                        })
                    })
                }
                break;
            case 'receive-group-chat': // 接收群聊消息事件
                console.log(' -------------- 接收群聊消息事件 -------------- ')
                // 如果当前页面是聊天页面,则发送设置消息为已读消息
                if (commonStore.currentRouteUrl == '/pages/chat/index') {
                    console.log(' +++++++++++++ 设置消息为已读 +++++++++++++ ')
                    // 设置消息为已读
                    data.is_read = 1
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })

                    // loadingInstance.value.close()
                    // 判断当前消息是否为当前用户发送,如果不是当前用户发送的消息则添加到消息列表
                    // 反之则不添加，因为在发送消息之前已经添加过了
                    if (data.from_uid != userStore.profile.user?.uid) {
                        messageList.value.unshift(data);
                    }
                    console.log('receive-group-chat =', data);
                }
                
                // 如果当前页面是首页,则将最后一条消息修改为当前消息
                if (commonStore.currentRouteUrl == '/pages/index/index') {
                    console.log(' +++++++++++++ 打开聊天对象 +++++++++++++ ')
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'open-chat-target',
                            uid: userStore.profile.user?.uid,
                            mode: 2,
                            target_info: {
                                target_id: data.to_uid
                            }
                        })
                    })
                }
                break;
            case 'receive-join-group-broadcast': // 接收加入群消息事件
                console.log(' -------------- 接收加入群消息事件 -------------- ')
                data.event_type = 'join-group'
                websocket.value.send({
                    data: JSON.stringify(data)
                })
                break;
            case 'receive-remove-group-broadcast': // 接收移除群消息事件
                console.log(' -------------- 接收移除群消息事件 -------------- ')
                data.event_type = 'remove-group'
                websocket.value.send({
                    data: JSON.stringify(data)
                })

                console.log('data = ', data);
                
                // 关闭聊天对象
                const indx = commonStore.chatTargetList.findIndex(item => item.target_info.target_id == data.group)
                console.log('indx = ', indx);
                commonStore.chatTargetList.splice(indx, 1)
                break;
            case 'receive-broadcast': // 接收广播消息事件
                console.log(' -------------- 接收广播消息事件 -------------- ')
                // loadingInstance.value.close()
                messageList.value.push(data);
                console.log('receive-broadcast =', data);
                break;
            case 'receive-open-chat-target': // 接收打开聊天对象事件
                console.log(' -------------- 接收打开聊天对象事件 -------------- ')
                // 获取聊天对象
                const index = commonStore.chatTargetList.findIndex(item => item.id == data.id)
                switch (data.message.type) {
                    case 2:
                        data.message.contents = '[图片]'
                        break;
                    case 3:
                        data.message.contents = '[语音]'
                        break;
                    case 4:
                        data.message.contents = '[视频]'
                        break;
                    case 5:
                        data.message.contents = '[位置]'
                        break;
                    
                    default:
                        break;
                    }
                if (index != -1) { // 编辑
                    data.unread_num = commonStore.chatTargetList[index].unread_num + 1
                    console.log('data = ', data);
                    
                    commonStore.editChatTarget(data)
                } else { // 添加
                    data.unread_num = 1
                    commonStore.addChatTarget(data)
                }
                break;
            case 'receive-group-notice': // 接收群公告事件
                console.log(' -------------- 接收群公告事件 -------------- ')
                // 如果当前页面是聊天页面,则发送设置消息为已读消息
                if (commonStore.currentRouteUrl == '/pages/chat/index') {
                    console.log(' +++++++++++++ 设置消息为已读 +++++++++++++ ')
                    // 设置消息为已读
                    data.is_read = 1
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })
                    // loadingInstance.value.close()
                    messageList.value.unshift(data)
                }
                break;
            case 'receive-friend-apply': // 接收好友申请通知事件
                console.log(' -------------- 接收好友申请通知事件 -------------- ')
                console.log('data = ', data);

                // loadingInstance.value.close()
                const total = commonStore.friendApplyTotal + 1
                commonStore.setFriendApplyTotal(total)
                break;
            case 'receive-server-notify': // 接收服务通知事件
                console.log(' --------------- 接收服务通知事件 --------------- ')
                console.log('data = ', data);
                commonStore.setNewestNotify(data)
                const unreadNotifyTotal = commonStore.unreadNotifyTotal + 1
                commonStore.setUnreadNotifyTotal(unreadNotifyTotal)
                break;
            case 'ping':
                // console.log('发送响应服务端心跳');
                websocket.value.send({
                    data: JSON.stringify({event_type: 'pong', create_time: dayjs().format('YYYY-MM-DD HH:mm:ss')})
                }); // 发送响应服务端心跳
                break;
            case 'pong':
                // console.log('来自服务端的心跳反馈');
                
                // 重置心跳超时定时器
                clearTimeout(heartbeatTimeoutId.value);
                break;
            default:
                break;
        }
    })

    // 监听错误事件
    websocket.value.onError((data: any) => {
        console.log('-------- Listen onError event --------')
        console.log('close data = ', data)
    })

    // 监听关闭事件
    websocket.value.onClose((data: any) => {
        console.log('-------- Listen onClose event --------')
        console.log('close data = ', data)
        

        // 连接关闭时清除定时器
        clearInterval(heartbeatIntervalId.value)
        clearTimeout(heartbeatTimeoutId.value)

        // 断线重连
        reconnect(reconnectInterval.value, maxRetries.value)
    })
    // #endif

    // 处理消息
    const handleMessage = (message: any) => {
        console.log('------- Listen onMessage event -------')
        const response = JSON.parse(message.data)
        // console.log('response = ', response)

        // 判断消息状态
        if (response.status_code != 200) {
            uni.showToast({
                title: response.msg,
                duration: 1000,
                icon: 'none'
            })
    
            return false
        }

        // 解析数据
        const data = response.data
        
        // 处理事件
        switch (data.event_type) {
            case 'receive-private-chat': // 接收私聊消息事件
                console.log(' -------------- 接收私聊消息事件 -------------- ')
                console.log('data =', data);
                // 如果当前页面是聊天页面,则发送设置消息为已读消息
                if (commonStore.currentRouteUrl == '/pages/chat/index') {
                    console.log(' +++++++++++++ 设置消息为已读 +++++++++++++ ')
                    // 设置消息为已读
                    data.is_read = 1
                    // #ifdef MP-ALIPAY
                    uni.sendSocketMessage({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })
                    // #else
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })
                    // #endif

                    // loadingInstance.value.close()
                    messageList.value.unshift(data);
                    console.log('receive-private-chat =', data);
                }

                // 如果当前页不是聊天页面,则打开对话框、将最后一条消息修改为当前消息
                if (commonStore.currentRouteUrl != '/pages/chat/index') {
                    console.log(' +++++++++++++ 打开聊天对象 +++++++++++++ ')

                    // 组装消息数据
                    const messageData = JSON.stringify({
                        event_type: 'open-chat-target',
                        uid: data.to_uid,
                        mode: 1,
                        target_info: {
                            name: data.from_user?.username,
                            target_id: data.from_user?.uid,
                            avatar_url: data.from_user?.avatar_url
                        }
                    })

                    // #ifdef MP-ALIPAY
                    uni.sendSocketMessage({data: messageData})
                    // #else
                    websocket.value.send({data: messageData})
                    // #endif
                }
                break;
            case 'receive-group-chat': // 接收群聊消息事件
                console.log(' -------------- 接收群聊消息事件 -------------- ')
                // 如果当前页面是聊天页面,则发送设置消息为已读消息
                if (commonStore.currentRouteUrl == '/pages/chat/index') {
                    console.log(' +++++++++++++ 设置消息为已读 +++++++++++++ ')
                    // 设置消息为已读
                    data.is_read = 1
                    // #ifdef MP-ALIPAY
                    uni.sendSocketMessage({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })
                    // #else
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })
                    // #endif

                    // loadingInstance.value.close()
                    // 判断当前消息是否为当前用户发送,如果不是当前用户发送的消息则添加到消息列表
                    // 反之则不添加，因为在发送消息之前已经添加过了
                    if (data.from_uid != userStore.profile.user?.uid) {
                        messageList.value.unshift(data);
                    }
                    console.log('receive-group-chat =', data);
                }
                
                // 如果当前页面是首页,则将最后一条消息修改为当前消息
                if (commonStore.currentRouteUrl == '/pages/index/index') {
                    console.log(' +++++++++++++ 打开聊天对象 +++++++++++++ ')

                    // 组装消息数据
                    const messageData = JSON.stringify({
                        event_type: 'open-chat-target',
                        uid: userStore.profile.user?.uid,
                        mode: 2,
                        target_info: {
                            target_id: data.to_uid
                        }
                    })

                    // #ifdef MP-ALIPAY
                    uni.sendSocketMessage({data: messageData})
                    // #else
                    websocket.value.send({data: messageData})
                    // #endif
                }
                break;
            case 'receive-join-group-broadcast': // 接收加入群消息事件
                console.log(' -------------- 接收加入群消息事件 -------------- ')
                data.event_type = 'join-group'
                // #ifdef MP-ALIPAY
                uni.sendSocketMessage({
                    data: JSON.stringify(data)
                })
                // #else
                websocket.value.send({
                    data: JSON.stringify(data)
                })
                // #endif
                break;
            case 'receive-remove-group-broadcast': // 接收移除群消息事件
                console.log(' -------------- 接收移除群消息事件 -------------- ')
                data.event_type = 'remove-group'
                // #ifdef MP-ALIPAY
                uni.sendSocketMessage({
                    data: JSON.stringify(data)
                })
                // #else
                websocket.value.send({
                    data: JSON.stringify(data)
                })
                // #endif

                console.log('data = ', data);
                
                // 关闭聊天对象
                const indx = commonStore.chatTargetList.findIndex(item => item.target_info.target_id == data.group)
                console.log('indx = ', indx);
                commonStore.chatTargetList.splice(indx, 1)
                break;
            case 'receive-broadcast': // 接收广播消息事件
                console.log(' -------------- 接收广播消息事件 -------------- ')
                // loadingInstance.value.close()
                messageList.value.push(data);
                console.log('receive-broadcast =', data);
                break;
            case 'receive-open-chat-target': // 接收打开聊天对象事件
                console.log(' -------------- 接收打开聊天对象事件 -------------- ')
                // 获取聊天对象
                const index = commonStore.chatTargetList.findIndex(item => item.id == data.id)
                switch (data.message.type) {
                    case 2:
                        data.message.contents = '[图片]'
                        break;
                    case 3:
                        data.message.contents = '[语音]'
                        break;
                    case 4:
                        data.message.contents = '[视频]'
                        break;
                    case 5:
                        data.message.contents = '[位置]'
                        break;
                    
                    default:
                        break;
                    }
                if (index != -1) { // 编辑
                    data.unread_num = commonStore.chatTargetList[index].unread_num + 1
                    console.log('data = ', data);
                    
                    commonStore.editChatTarget(data)
                } else { // 添加
                    data.unread_num = 1
                    commonStore.addChatTarget(data)
                }
                break;
            case 'receive-group-notice': // 接收群公告事件
                console.log(' -------------- 接收群公告事件 -------------- ')
                // 如果当前页面是聊天页面,则发送设置消息为已读消息
                if (commonStore.currentRouteUrl == '/pages/chat/index') {
                    console.log(' +++++++++++++ 设置消息为已读 +++++++++++++ ')
                    // 设置消息为已读
                    data.is_read = 1

                    // #ifdef MP-ALIPAY
                    uni.sendSocketMessage({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })
                    // #else
                    websocket.value.send({
                        data: JSON.stringify({
                            event_type: 'read-message',
                            id: data.id
                        })
                    })
                    // #endif
                    // loadingInstance.value.close()
                    messageList.value.unshift(data)
                }
                break;
            case 'receive-friend-apply': // 接收好友申请通知事件
                console.log(' -------------- 接收好友申请通知事件 -------------- ')
                console.log('data = ', data);

                // loadingInstance.value.close()
                const total = commonStore.friendApplyTotal + 1
                commonStore.setFriendApplyTotal(total)
                break;
            case 'receive-server-notify': // 接收服务通知事件
                console.log(' --------------- 接收服务通知事件 --------------- ')
                console.log('data = ', data);
                commonStore.setNewestNotify(data)
                const unreadNotifyTotal = commonStore.unreadNotifyTotal + 1
                commonStore.setUnreadNotifyTotal(unreadNotifyTotal)
                break;
            case 'ping':
                // console.log('发送响应服务端心跳')
                // 发送响应服务端心跳
                // #ifdef MP-ALIPAY
                uni.sendSocketMessage({
                    data: JSON.stringify({event_type: 'pong', create_time: dayjs().format('YYYY-MM-DD HH:mm:ss')})
                })
                // #else
                websocket.value.send({
                    data: JSON.stringify({event_type: 'pong', create_time: dayjs().format('YYYY-MM-DD HH:mm:ss')})
                })
                // #endif
                break;
            case 'pong':
                // console.log('来自服务端的心跳反馈')
                
                // 重置心跳超时定时器
                clearTimeout(heartbeatTimeoutId.value)
                break;
            default:
                break;
        }
    }
}
// ------------ 初始化 websocket 结束 ------------



// --------------- 重新连接功能开始 ---------------
const reconnect = (intervalTime: number, reconnectCount: number) => {
    console.log('重连次数 =', retries.value)
    console.log('reconnectCount =', reconnectCount)
    
    if (retries.value < reconnectCount) {
        console.log('重连中...');
        setTimeout(initWebSocket, intervalTime)
        retries.value++
    }
}
// --------------- 重新连接功能结束 ---------------



// --------------- 心跳检测功能开始 ---------------
const startHeartbeat = () => {
    heartbeatIntervalId.value = setInterval(function() {
        // 发送心跳包
        // #ifdef MP-ALIPAY
        uni.sendSocketMessage({
            data: JSON.stringify({event_type: 'ping', create_time: dayjs().format('YYYY-MM-DD HH:mm:ss')}),
            success: () => {
                // console.log('发送心跳成功...');
            },
            fail: () => {
                console.log('发送心跳失败...');
            }
        })
        // #else
        websocket.value.send({
            data: JSON.stringify({event_type: 'ping', create_time: dayjs().format('YYYY-MM-DD HH:mm:ss')}),
            success: () => {
                // console.log('发送心跳成功...');
            },
            fail: () => {
                console.log('发送心跳失败...');
            }
        })
        // #endif

        // 重置心跳超时定时器
        clearTimeout(heartbeatTimeoutId.value)
        heartbeatTimeoutId.value = setTimeout(function() {
            console.log('Heartbeat timeout, closing the connection.')

            // 超时未收到响应，关闭连接
            // #ifdef MP-ALIPAY
            uni.closeSocket()
            // #else
            websocket.value.close()
            // #endif
            // 这里可以添加重新连接的逻辑
        }, heartbeatTimeout)
    }, heartbeatInterval)
}
// --------------- 心跳检测功能开始 ---------------



// ------------- 处理关闭连接功能开始 -------------
export const handleCloseConn = () => {
    retries.value = 5
    // #ifdef MP-ALIPAY
    uni.closeSocket({complete: () => {
        console.log('++++++++ 关闭 WebSocket 连接 ++++++++');
    }})
    // #else
    websocket.value.close({complete: () => {
        console.log('++++++++ 关闭 WebSocket 连接 ++++++++');
    }})
    // #endif
}
// ------------- 处理关闭连接功能结束 -------------